<?php
/**
 * Greendizer PHP Library
 * 
 * @category    Greendizer
 * @package     Greendizer_DAL
 * @copyright   Copyright (c) 2009-2010, Greendizer S.A - All rights reserved.
 * @license     Greendizer/Licence.txt
 * @version     1.0
 */

/**
 * @see Greendizer_Client
 */
require_once 'Greendizer/Client.php';
/**
 * @see Greendizer_Net_Request
 */
require_once 'Greendizer/Net/Request.php';
/**
 * @see Greendizer_Net_Request
 */
require_once 'Greendizer/Net/Response.php';
/**
 * @see Greendizer_Net_Response
 */
require_once 'Greendizer/Net/HttpStatusCodes.php';
/**
 * @see Greendizer_Net_HttpStatusCodes
 */
require_once 'Greendizer/Net/HttpMethods.php';
/**
 * @see Greendizer_Net_Etag
 */
require_once 'Greendizer/Net/Etag.php';
/**
 * @see Greendizer_Net_Exception
 */
require_once 'Greendizer/Net/Exception.php';
/**
 * @see Greendizer_DAL_Exception
 */
require_once 'Greendizer/DAL/Exception.php';

/**
 * Represents a Resource
 * 
 * @category    Greendizer
 * @package     Greendizer_DAL
 * @copyright   Copyright (c) 2009-2010, Greendizer S.A - All rights reserved.
 * @license     Greendizer/License.txt
 */
abstract class Greendizer_DAL_Resource {

    /**
     * ID of the resource
     *
     * @var string 
     */
    private $id;
    
    /**
     * Last Modified date
     *
     * @var string
     */
    private $lastModified;
    
    /**
     * Resource Client
     *
     * @var Greendizer_DAL_Client
     */
    private $client;
    
    /**
     * Resource Etag
     * 
     * @var Greendizer_Net_Etag
     */
    private $etag;
    
    /**
     * Array of resource properties
     *
     * @var array
     */
    private $resourceProperties = array();
    
    /**
     * Array of updated resource properties
     *
     * @var array
     */
    private $updatedProperties = array();

    /**
     * Initializes a new resource object
     *
     * @param Greendizer_Client $client Client accessing the resource
     * @param string $id Resource identifier
     */
    public function __construct(Greendizer_Client $client, $id = null) {
        $this->client = $client;
        $this->id = $id;      
    }
    
    /**
     * Returns the resource Etag
     *
     * @return Greendizer_Net_Etag
     */
    public function getEtag(){
        return $this->etag;
    }

    /**
     * Returns the resource ID
     *
     * @return string
     */
    public function getId() {
        return $this->id;
    }

    /**
     * Returns the resource Client
     *
     * @return Greendizer_Client
     */
    public function getClient() {
        return $this->client;
    }

    /**
     * Returns the resource Uri
     * 
     * @return Greendizer_Net_Uri
     */
    protected function getUri() {

        throw new Exception('Function not implemented');
    }

    /**
     * Saves the resource to the server
     * 
     * @throws Greendizer_Net_Exception
     */
    public function save() {
        //send a request for the resource
        $headers = array(
            'Accept' => 'application/json',
            'If-Unmodified-Since' => $this->etag->getLastModified(),
            'If-Match' => $this->etag->getEtagString()
        );
        $request = new Greendizer_Net_Request(
                        Greendizer_Net_HttpMethods::PATCH,
                        $this->getUri(),
                        $headers,
                        $this->client->getAuthType(),
                        $this->client->getCredentials(),
                        http_build_query($this->updatedProperties)
        );
        
        $response = $request->getResponse();
        //If the response is fine, Keep the new etag
        if ($response->getStatusCode() == Greendizer_Net_HttpStatusCodes::HTTP_NO_CONTENT) {
            $this->etag = Greendizer_Net_Etag::parseEtagString($response->getHeader('etag'));
            $this->id = $this->etag->getId();
            $this->lastModified = $this->etag->getLastModified();
            //flush the updated as they were synced
            $this->updatedProperties = array();
            return;
        }
        throw new Greendizer_Net_Exception($response->getStatusCode() .': ' .Greendizer_Net_HttpStatusCodes::getStatusMessageForCode($response->getStatusCode()) );
    }

    /**
     * Deletes a resource from the server
     *
     * @throws Greendizer_Net_Exception 
     */
    public function delete() {
        //send a request for the resource
        $headers = array(
            'Accept' => 'application/json',
            'If-Unmodified-Since' => $this->etag->getLastModified(),
            'If-Match' => $this->etag->getEtagString()
        );
        $request = new Greendizer_Net_Request(
                        Greendizer_Net_HttpMethods::DELETE,
                        $this->getUri(),
                        $headers,
                        $this->client->getAuthType(),
                        $this->client->getCredentials());
        $response = $request->getResponse();
        //If the response is fine return
        if ($response->getStatusCode() == Greendizer_Net_HttpStatusCodes::HTTP_NO_CONTENT) {
            return;
        }
        throw new Greendizer_Net_Exception($response->getStatusCode() .': ' .Greendizer_Net_HttpStatusCodes::getStatusMessageForCode($response->getStatusCode()) );
    }

    /**
     * Refreshes the resource properties
     *
     * @return Greeendizer_Net_Exception 
     */
    public function refresh() {
        //send a request for the resource

        $headers = array(
            'Accept' => 'application/json',
                //'If-Match' => $this->etag->getEtagString(),
                //'If-Modified-Since' => $this->etag->getLastModified(),
        );
        $request = new Greendizer_Net_Request(
                        Greendizer_Net_HttpMethods::GET,
                        $this->getUri(),
                        $headers,
                        $this->client->getAuthType(),
                        $this->client->getCredentials());
        $response = $request->getResponse();
        //If the response is fine, sync
        if ($response->getStatusCode() == Greendizer_Net_HttpStatusCodes::HTTP_OK) {
            $this->sync(json_decode($response->getData()), Greendizer_Net_Etag::parseEtagString($response->getHeader('etag')));
            return;
        }
        throw new Greendizer_Net_Exception($response->getStatusCode() .': ' .Greendizer_Net_HttpStatusCodes::getStatusMessageForCode($response->getStatusCode()) );
    }

    /**
     * Synchronizes the object properties with an array of properties
     *
     * @param array $jsonDecodedData array of object properties
     * @param Greendizer_Net_Etag $etag resource Etag
     */
    public function sync($jsonDecodedData, Greendizer_Net_Etag $etag=null) {
        //Get Etag and update fields
        if ($etag != null) {
            $this->etag = $etag;
            $this->id = $etag->getId();
            $this->lastModified = $etag->getLastModified();
        }


        //Add the json parsed properties
        foreach ($jsonDecodedData as $key => $value) {
            $this->resourceProperties[$key] = $value;
        }
    }

    /**
     * Sets resource property
     *
     * @param string $name  property name
     * @param string $value property value
     */
    public function __set($name, $value) {
        if(!(array_key_exists($name, $this->updatedProperties) && $this->updatedProperties[$name] == $value)){
            $this->updatedProperties[$name] = $value;
        }
        
        $this->resourceProperties[$name] = $value;

    }

    /**
     * Gets resource property value
     *
     * @param string $name  property name
     * @return string
     * @throws Greendizer_DAL_Exception
     */
    public function __get($name) {
        if (array_key_exists($name, $this->resourceProperties)) {
            return $this->resourceProperties[$name];
        }
        return null;
    }

    /**
     * String representation of the resource object
     *
     * @return string  
     */
    public function toString() {
        return 'Resource: ' . $this->getUri();
    }

}

?>